Skip to content

fix: Stop polling an action attempt once the timeout passes - #572

Open
razor-x wants to merge 1 commit into
mainfrom
claude/ruby-sdk-audit-xbhaia-poll-deadline
Open

fix: Stop polling an action attempt once the timeout passes#572
razor-x wants to merge 1 commit into
mainfrom
claude/ruby-sdk-audit-xbhaia-poll-deadline

Conversation

@razor-x

@razor-x razor-x commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

SDK audit finding H2. ActionAttemptResolver.wait_until_resolved advanced its clock only by polling_interval:

  • polling_interval: 0 never advanced the clock, so the timeout never fired and the loop polled /action_attempts/get without pause.
  • Time spent waiting on the API never counted, so a "5 second" timeout could block for minutes against a slow server and then raise an error claiming it timed out after 5s.
  • Every wait overran the timeout by one full interval.

Fix

Poll against a monotonic deadline (ported from the python fix, seamapi/python#635):

  • sleep([polling_interval, remaining].min), then poll, then time out only once the deadline has actually passed. A wait still polls once when the timeout is shorter than the polling_interval.
  • Validate up front with Seam::Http::Options::SeamInvalidOptionsError: The timeout option must not be negative, got X and The polling_interval option must be greater than zero, got X. The checks are written as negated comparisons so NaN is rejected too.

README documents the deadline behavior and the option constraints.

Tests

New spec/seam_client/action_attempt_polling_spec.rb against the raw request recorder (which gained an optional response delay:) asserts the exact error messages, that a rejected option makes no poll request, that a short timeout still polls exactly once, and that slow responses count against the deadline.

Revert-check against the previous resolver: the interval-zero spec hangs, the slow-response spec takes 1.8s against a 0.5s timeout, and the short-timeout spec sleeps the full 3s interval.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97


Generated by Claude Code

The wait loop advanced its clock only by the polling interval, so a
polling_interval of zero never timed out and polled without pause, the
time spent waiting on the API never counted against the timeout, and every
wait overran the timeout by one interval.

Poll against a monotonic deadline, sleeping the shorter of the interval
and the remaining budget, so the wait still polls once when the timeout is
shorter than the interval and stops as soon as the deadline passes. Reject
a negative timeout and a polling interval that is not greater than zero
with the SDK's invalid options error before the first poll.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants